﻿using System;
using System.Configuration;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using GMS.Core.Config.Models;
using Image = System.Drawing.Image;
using System.Drawing.Imaging;

namespace GMS.Core.Upload
{
    public abstract class CoreUploadHandler : IHttpHandler
    {
        /// <summary>
        /// 机构小节课程讲义PDF上传文件最大5M
        /// </summary>
        private int PDF_MAX_FILE_SIZE = 5242880;

        public bool IsReusable
        {
            get { return false; }
        }

        public virtual string FileInputName
        {
            get { return "file_data"; }
        }

        public string UploadPath
        {
            get { return UploadConfigContext.UploadPath; }
        }

        public int MaxFilesize
        {
            //10M -- 100M
            //get { return 10971520; }
            get { return 1048576000; }
        }

        public virtual string[] AllowExt
        {
            get
            {
                return new string[]
                {
                    //1.增加ipa
                    "txt", "rar", "zip", "jpg", "jpeg", "gif", "png", "swf", "mp4", "flv", "rmvb", "apk", "xlsx", "pptx",
                    "ppt", "docx", "doc","xls","pdf","ipa"
                };
            }
        }

        public virtual string[] ImageExt
        {
            get
            {
                return new string[]
                {
                    "jpg", "jpeg", "gif", "png", "apk", "xlsx", "pptx",
                    "ppt", "docx", "doc","xls","pdf"
                };
            }
        }

        public string[] MyImageExt
        {
            get
            {
                return new string[]
                {
                    "jpg", "jpeg", "gif", "png"
                };
            }
        }

        public abstract string GetResult(string localFileName, string uploadFilePath, string uploadFilePath_s, string err);
        public abstract string OnUploaded(HttpContext context, string filePath);
        public abstract string FindOldPath(string ext, out int systemVersionId);
        public abstract void UpdtOldPath(string path, int systemVersionId);

        public void ProcessRequest(HttpContext context)
        {
            context.Response.Charset = "UTF-8";
            byte[] file;
            var localFileName = string.Empty;
            var err = string.Empty;
            var subFolder = string.Empty;
            var fileFolder = string.Empty;
            var filePath = string.Empty;
            var path_s = string.Empty;
            var disposition = context.Request.ServerVariables["HTTP_CONTENT_DISPOSITION"];
            if (disposition != null)
            {
                // HTML5上传
                file = context.Request.BinaryRead(context.Request.TotalBytes);
                localFileName = Regex.Match(disposition, "filename=\"(.+?)\"").Groups[1].Value;// 读取原始文件名
            }
            else
            {
                var filecollection = context.Request.Files;
                var postedfile = filecollection.Get(this.FileInputName);

                // 读取原始文件名
                localFileName = Path.GetFileName(postedfile.FileName);
                // 初始化byte长度.
                file = new byte[postedfile.ContentLength];

                // 转换为byte类型
                var stream = postedfile.InputStream;
                stream.Read(file, 0, postedfile.ContentLength);
                stream.Close();

                filecollection = null;
            }

            var ext = localFileName.Substring(localFileName.LastIndexOf('.') + 1).ToLower();

            if (file.Length == 0)
                err = "无数据提交";
            else if (file.Length > this.MaxFilesize)
                err = "文件大小超过" + this.MaxFilesize + "字节";
            else if (!AllowExt.Contains(ext))
                err = "上传文件扩展名必需为：" + string.Join(",", AllowExt);
            else
            {
                var folder = context.Request["subfolder"] ?? "default"; //文件夹
                var uploadFolderConfig = UploadConfigContext.UploadConfig.UploadFolders.FirstOrDefault(u => string.Equals(folder, u.Path, StringComparison.OrdinalIgnoreCase));
                var dirType = uploadFolderConfig == null ? DirType.Day : uploadFolderConfig.DirType;

                //根据配置里的DirType决定子文件夹的层次（月，天，扩展名）
                switch (dirType)
                {
                    case DirType.Month:
                        subFolder = "month_" + DateTime.Now.ToString("yyMM");
                        break;
                    case DirType.Ext:
                        subFolder = "ext_" + ext;
                        break;
                    case DirType.Day:
                        subFolder = "day_" + DateTime.Now.ToString("yyMMdd");
                        break;
                }
                switch (ext)
                {
                    case "apk":
                        subFolder = "apk";
                        break;
                    case "ipa":
                        subFolder = "ipa";
                        break;
                }
                fileFolder = HttpContext.Current.Server.MapPath("~/FilesServer");//同一服务器的绝对路径
                var oldPath = "";
                var systemVersionId = 0;

                //重命名后的相对路径
                var path = Path.Combine(folder, subFolder,
                                    string.Format("{0}{1}.{2}", DateTime.Now.ToString("yyyyMMddhhmmss"),
                                    new Random(DateTime.Now.Millisecond).Next(10000), ext));
                //重命名后的绝对路径
                var newPath = Path.Combine(fileFolder, path);
                //路径处理替换/
                path = path.Replace("\\", "/");
                //路径处理开头加上“/”
                path = path.Insert(0, "/");
                //重新定义apk或ipa的fileFolder，与其他有所区别
                fileFolder = Path.Combine(fileFolder, folder, subFolder);
                switch (ext)
                {
                    case "apk":
                        //执行旧文件重命名和新文件改名
                        if (OldFileRename(oldPath, newPath))
                        {
                            //改名成功后更新数据库
                            UpdtOldPath(path, systemVersionId);
                        }
                        //上传新文件并且改名
                        filePath = Path.Combine(fileFolder,
                            string.Format("{0}.{1}",
                                "TopHuiKaoBaAPP",
                                ext));
                        break;
                    case "ipa":
                        //执行旧文件重命名
                        if (OldFileRename(oldPath, newPath))
                        {
                            //改名成功后更新数据库
                            UpdtOldPath(path, systemVersionId);
                        }
                        //上传新文件并且改名
                        filePath = Path.Combine(fileFolder,
                        string.Format("{0}.{1}",
                                    "TopHuiKaoBaIOS",
                                    ext));
                        break;
                    default:
                        filePath = Path.Combine(fileFolder,
                        string.Format("{0}{1}.{2}",
                                    DateTime.Now.ToString("yyyyMMddhhmmss"),
                                    new Random(DateTime.Now.Millisecond).Next(10000), ext)
                        );
                        break;
                }
                if (!Directory.Exists(fileFolder))
                {
                    Directory.CreateDirectory(fileFolder);
                }
                var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write);

                //如果是图片则判断是否符合尺寸要求
                if (MyImageExt.Contains(ext))
                {
                    if (!string.IsNullOrEmpty(context.Request["limit"]))
                    {
                        //限制上传图片尺寸（像素值）
                        var ms = new MemoryStream(file);
                        var img = Image.FromStream(ms);
                        var limitpoint = context.Request["limit"];
                        var limitWidth = Convert.ToInt32(limitpoint.Split('*').First());
                        var limitHeigth = Convert.ToInt32(limitpoint.Split('*').Last());
                        var width = img.Size.Width;   // 图片的宽度
                        var height = img.Size.Height;   // 图片的高度
                        if (width != limitWidth || height != limitHeigth)
                        {
                            err = string.Format("图片尺寸不正确！建议图片宽为{0}px,长为{1}px", limitWidth, limitHeigth);
                        }
                    }
                    fs.Write(file, 0, file.Length);
                    fs.Flush();
                }
                else if ("pdf".Equals(ext.ToLower()) && file.Length > PDF_MAX_FILE_SIZE)
                {
                    var fileSizeM = PDF_MAX_FILE_SIZE / 1024 / 1024;
                    err = "文件大小超过" + fileSizeM.ToString() + "MB";
                }
                else
                {
                    fs.Write(file, 0, file.Length);
                    fs.Flush();
                }
                fs.Close();

                //是图片，即使生成对应尺寸
                if (MyImageExt.Contains(ext))
                    ThumbnailService.HandleImmediateThumbnail(filePath);
                path_s = this.OnUploaded(context, filePath);
            }

            file = null;
            var a = this.GetResult(localFileName, filePath, path_s, err);
            context.Response.Write(a);
            context.Response.End();
        }

        //旧版本重命名
        //重命名之前上传文件
        public bool OldFileRename(string srcRelativePath, string desRelativePath)
        {
            if (File.Exists(srcRelativePath))
            {
                File.Move(srcRelativePath, desRelativePath);
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 图片剪切上传
        /// </summary>
        /// <param name="file">图片</param>
        /// <param name="folder">相对文件夹</param>
        /// <returns>返回图片相对路径</returns>
        public static string UpLoadCropImg(string file, string folder)
        {
            ImageCodecInfo myImageCodecInfo = GetEncoderInfo("image/jpeg");
            Encoder myEncoder = Encoder.Quality; ;
            EncoderParameter myEncoderParameter=new EncoderParameter(myEncoder, 100L);
            EncoderParameters myEncoderParameters = new EncoderParameters(1);
            myEncoderParameters.Param[0] = myEncoderParameter;
            string fileFolder = string.Empty;
            //获取图片存储服务器地址
            fileFolder = HttpContext.Current.Server.MapPath("~/FilesServer");
            //同一服务器的绝对路径
            string path = Path.Combine(folder, "day_" + DateTime.Now.ToString("yyMMdd"),
                                    string.Format("{0}{1}.{2}", DateTime.Now.ToString("yyyyMMddhhmmss"),
                                    new Random(DateTime.Now.Millisecond).Next(10000), "jpg"));
            //重命名后的绝对路径
            var newPath = Path.Combine(fileFolder, path);
            //路径处理替换/
            path = path.Replace("\\", "/");
            //路径处理开头加上“/”
            path = path.Insert(0, "/");  //生成图片名称
            //要存储的图片路径,判断是否存在，如果不存在就新建文件夹
            var fileSavePath = Path.Combine(string.Format("{0}\\{1}", fileFolder, folder), "day_" + DateTime.Now.ToString("yyMMdd"));

            if (!Directory.Exists(fileSavePath))
            {
                Directory.CreateDirectory(fileSavePath);
            }
            byte[] arr = Convert.FromBase64String(file);
            MemoryStream ms = new MemoryStream(arr);
            Image bmp = new Bitmap(ms);
            bmp.Save(newPath, myImageCodecInfo, myEncoderParameters);          
            return path;
        }

        /// <summary>
        /// 控制图片类型 类型符合则返回编码
        /// </summary>
        private static ImageCodecInfo GetEncoderInfo(String mimeType)
        {
            ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
            for (int j = 0; j < encoders.Length; ++j)
            {
                if (encoders[j].MimeType == mimeType)
                {
                    return encoders[j];
                }
            }
            //不符合返回null
            return null;
        }
    }
}
